﻿using BencodeNET.Objects;
using Furion.DependencyInjection;
using Microsoft.AspNetCore.Http;
using PrivateTracker.Service.Core;
using System.Net;

namespace PrivateTracker.Service.Application;
/// <summary>
/// 
/// </summary>
public class AnnounceService : IAnnounceService, ITransient
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly IPeerService _peerService;
    private readonly IClientService _clientService;
    private readonly ITorrentService _torrentService;
    private readonly ISysUserService _sysUserService;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="httpContextAccessor"></param>
    /// <param name="peerService"></param>
    /// <param name="clientService"></param>
    /// <param name="torrentService"></param>
    public AnnounceService(IHttpContextAccessor httpContextAccessor, IPeerService peerService, IClientService clientService, ITorrentService torrentService, ISysUserService sysUserService)
    {
        _httpContextAccessor = httpContextAccessor;
        _peerService = peerService;
        _torrentService = torrentService;
        _clientService = clientService;
        _sysUserService = sysUserService;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public async Task<BDictionary> GetAnnounceOutputAsync(AnnounceInput input)
    {
        //客户端验证
        bool isAllowClinet = await _clientService.IsAllowClinet(input.GetAgent());
        if (!isAllowClinet)
        {
            return await Task.FromResult<BDictionary>(new BDictionary() { { TrackerConsts.FailureKey, new BString("所使用的客户端不支持.") } });
        }
        if (string.IsNullOrWhiteSpace(input.Info_Hash) || input.Info_Hash.Length != 40)
        {
            return await Task.FromResult<BDictionary>(new BDictionary() { { TrackerConsts.FailureKey, new BString("不符合Tracker协议规范.") } });
        }
        if (!IPAddress.TryParse(input.GetIPv4(), out IPAddress ipAddress) || input.Port == 0)
        {
            return await Task.FromResult<BDictionary>(new BDictionary() { { TrackerConsts.FailureKey, new BString("不符合网络协议规范.") } });
        }
        if (string.IsNullOrWhiteSpace(input.Peer_Id) || input.Peer_Id.Length != 40)
        {
            return await Task.FromResult<BDictionary>(new BDictionary() { { TrackerConsts.FailureKey, new BString("客户端不符合规范.") } });
        }
        var user = await _sysUserService.GetUserByPassKeyAsync(input.PassKey);
        if (null == user)
        {
            return await Task.FromResult<BDictionary>(new BDictionary() { { TrackerConsts.FailureKey, new BString("非法的PassKey.") } });
        }
        if (user.IsDeleted)
        {
            return await Task.FromResult<BDictionary>(new BDictionary() { { TrackerConsts.FailureKey, new BString("禁用的PassKey.") } });
        }
        var torrent = await _torrentService.GetAsync(input.Info_Hash, user.TenantId);
        if (null == torrent)
        {
            return await Task.FromResult<BDictionary>(new BDictionary() { { TrackerConsts.FailureKey, new BString("资源未在该服务器上注册，请先发布资源.") } });
        }
        //删除停止的peer
        if (input.Event == PeerEvent.Stopped)
        {
            if (input.Left == 0) //已完成后暂停
            {
                await _torrentService.UpdaeCompleteCountAsync(input.Info_Hash, user.TenantId, -1);
            }
            else  //下载中暂停的 有剩余量
            {
                await _torrentService.UpdaeInCompleteCountAsync(input.Info_Hash, user.TenantId, -1);
            }
            //删除peer
            await _peerService.DeletePeerAsync(torrent.Id, input.Peer_Id);
        }
        //完成做种中
        if (input.Event == PeerEvent.Completed || (input.Left == 0 && input.Event == PeerEvent.Started))
        {
            await _torrentService.UpdaeCompleteCountAsync(input.Info_Hash, user.TenantId, 1);
        }
        else //下载中
        {
            await _torrentService.UpdaeInCompleteCountAsync(input.Info_Hash, user.TenantId, 1);
        }
        //添加后返回所有
        var peers = await _peerService.AddPeerAsync(input, torrent.Id);
        if (null != peers && peers.Any())
        {
            var total = Math.Min(peers.Count, input.Numwant.Value);
            // 判断当前 BT 客户端是否需要紧凑模式的数据。
            if (input.Compact == 1)
            {
                var compactResponse = new byte[total * 6];
                for (int index = 0; index < total; index++)
                {
                    var peer = peers.ElementAt(index);
                    Buffer.BlockCopy(peer.ToBytes(), 0, compactResponse, index * 6, 6);
                }
                var keyValues = new BDictionary();
                keyValues.Add(TrackerConsts.PeersKey, new BString(compactResponse));
                // 客户端等待时间
                keyValues.Add(TrackerConsts.IntervalKey, new BNumber((int)TimeSpan.FromSeconds(1800).TotalSeconds));
                // 最小等待间隔
                keyValues.Add(TrackerConsts.MinIntervalKey, new BNumber((int)TimeSpan.FromSeconds(1800).TotalSeconds));
                // Tracker 服务器的 Id
                keyValues.Add(TrackerConsts.TrackerIdKey, new BString("Tracker"));
                // 完成的 Peer 数量 
                keyValues.Add(TrackerConsts.CompleteKey, new BNumber(100));//TODO
                                                                           // 未完成的 Peer 数量
                keyValues.Add(TrackerConsts.IncompleteKey, new BNumber(23));//TODO
                return await Task.FromResult<BDictionary>(keyValues);
            }
            else
            {
                var item = new BList();
                for (int index = 0; index < total; index++)
                {
                    var peer = peers.ElementAt(index);
                    var dic = new BDictionary
                            {
                                {TrackerConsts.PeerIdKey,new BString(peer.PeerId)},
                                {TrackerConsts.Ip,new BString(peer.Ip)},
                                {TrackerConsts.Port,new BNumber(peer.Port) }
                            };
                    item.Add(dic);
                }
                return await Task.FromResult<BDictionary>(new BDictionary() { { TrackerConsts.PeersKey, item } });
            }
        }
        return await Task.FromResult<BDictionary>(new BDictionary() { });
    }
}